{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "Регулярные выражения.ipynb",
      "provenance": [],
      "collapsed_sections": [],
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/Afanasyy/colab/blob/main/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "h2UOt8sPsBfJ"
      },
      "source": [
        "# Регулярные выражения\n",
        "\n",
        "Регулярное выражение — это строка, задающая шаблон поиска подстрок в тексте. Одному шаблону может соответствовать много разных строчек. \n",
        "\n",
        "Термин «Регулярные выражения» является переводом английского словосочетания «Regular expressions». \n",
        "\n",
        "Регулярное выражение, или коротко «регулярка», состоит из обычных символов и специальных командных последовательностей. Например, `\\d` задаёт любую цифру, а `\\d+` — задает любую последовательность из одной или более цифр. Работа с регулярками реализована во всех современных языках программирования. Однако существует несколько «диалектов», поэтому функционал регулярных выражений может различаться от языка к языку."
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Когда могут быть необходимы\n",
        "\n",
        "Мы можем написать нужный нам шаблон (регулярку) и таким образом искать, а затем работать с найденными подстроками: изменять, заменять и т.д."
      ],
      "metadata": {
        "id": "HTtzVyxD-W-u"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Примеры регулярных выражений\n",
        "\n",
        "| Пример | Подходящие тексты                   |\n",
        "|--------|-------------------------------------|\n",
        "| м.л.ко | \"молоко\", \"малако\", \"м4леко\" и т.д. |\n",
        "| \\d{4}  | \"9867\", \"1234\", \"4322\" и т.д.       |"
      ],
      "metadata": {
        "id": "4Kp23jnuAEoO"
      }
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TMiYtkucszvH"
      },
      "source": [
        "## Основы синтаксиса\n",
        "\n",
        "Любая строка сама по себе является регулярным выражением. \n",
        "\n",
        "Так, выражению `Хаха` будет соответствовать строка `Хаха` и только она. \n",
        "\n",
        "Регулярные выражения являются регистрозависимыми, поэтому строка `хаха` (с маленькой буквы) уже не будет соответствовать выражению выше. Подобно строкам в языке Python, регулярные выражения имеют спецсимволы `.^$*+?{}[]\\|()`, которые в регулярках являются управляющими конструкциями."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "y39A6PHsuRjs"
      },
      "source": [
        "## Спецсимволы и управляющие конструкции\n",
        "\n",
        "![image.png]()"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "![image.png]()"
      ],
      "metadata": {
        "id": "eYK2uqXckmaE"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Квантификаторы (указатели количества повторений)\n",
        "\n",
        "![image.png]()"
      ],
      "metadata": {
        "id": "TE5eb4YzC0CV"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Экранирование специальных символов\n",
        "\n",
        "Если есть необходимость найти в тексте именно специальные символы (`.^$*+?{}[]\\|()`) как части строки, а не использовать как специальный символ регулярных выражений, их необходимо *экранировать*:\n",
        "\n",
        "* `\\.` - будет соответствовать обычному символу \"точка\";\n",
        "* `\\{\\}` - будет соответствовать последовательности символов {}, а не использоваться как часть квантификатора;\n",
        "* и т.д."
      ],
      "metadata": {
        "id": "GGh8E4HGjYUs"
      }
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wpiP2bMqxFLV"
      },
      "source": [
        "## Регулярные выражения в Python\n",
        "\n",
        "Для работы с регулярными выражениями в ЯП Python есть встроенный модуль `re`."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "mnRRap27xiCX"
      },
      "source": [
        "import re"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Доступные функции\n",
        "\n",
        "![image.png]()"
      ],
      "metadata": {
        "id": "XcRXIlsgnGVU"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### `search`\n",
        "\n",
        "Чтобы найти подстроку по некоторому шаблону, можно использовать функцию `search`.\n",
        "\n",
        "**NB**: Если под шаблон подходят несколько подстрок, только *первая* из них будет возвращена."
      ],
      "metadata": {
        "id": "hTIqjv_8nZBo"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "text = 'Телефон 123-12-12'\n",
        "regexp = r'\\d\\d\\D\\d\\d'\n",
        "\n",
        "match = re.search(regexp, text) \n",
        "print(match[0] if match else 'Not found') "
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "l5lk__X1nflz",
        "outputId": "d495401d-622d-4978-d6fa-474a0bdfb6ba"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "23-12\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "text = 'Телефон 1231212'\n",
        "\n",
        "match = re.search(regexp, text) \n",
        "print(match[0] if match else 'Not found') "
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "UDKUtbHPo50g",
        "outputId": "794b616a-180a-423d-a5a8-c26b98721432"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Not found\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### `fullmatch`\n",
        "\n",
        "Чтобы проверить соответствие некоторой строки некоторому шаблону, можно использовать функцию `fullmatch`."
      ],
      "metadata": {
        "id": "ArIgz4nkob6s"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "text = '12-12'\n",
        "regexp = r'\\d\\d\\D\\d\\d'\n",
        "\n",
        "match = re.fullmatch(regexp, text) \n",
        "print('YES' if match else 'NO')"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "3hQ4qXLgozwT",
        "outputId": "513d3e30-db9a-4b39-c813-113195f82a10"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "YES\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "text = 'Т. 12-12'\n",
        "\n",
        "match = re.fullmatch(r'\\d\\d\\D\\d\\d', text) \n",
        "print('YES' if match else 'NO')"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "MxlRSVPco9DD",
        "outputId": "663ed103-51df-490d-be3c-1b7d621cf91f"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "NO\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### `split`\n",
        "\n",
        "Чтобы разделить строку по некоторому шаблону, можно использовать функцию `split`."
      ],
      "metadata": {
        "id": "Zn6u3IEQpYsi"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "text = 'Где, скажите мне, мои очки??!'\n",
        "regexp = r'\\W+'\n",
        "\n",
        "result = re.split(regexp, text)\n",
        "print(result)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "EXIP9AkYpYE7",
        "outputId": "36946831-7607-4481-f574-220c964e45fc"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "['Где', 'скажите', 'мне', 'мои', 'очки', '']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### `findall`\n",
        "\n",
        "Чтоыб найти все подстроки по некоторому шаблону, можно использовать функцию `findall`."
      ],
      "metadata": {
        "id": "jwvAthhBq1DT"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "text = 'Эта строка написана 04.01.2022, а могла бы и 12.12.2021'\n",
        "regexp = r'\\d\\d\\.\\d\\d\\.\\d{4}'\n",
        "\n",
        "result = re.findall(regexp, text)\n",
        "print(result)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "znYyCRgBpYDO",
        "outputId": "98f0b581-01be-472a-f824-d569981a3484"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "['04.01.2022', '12.12.2021']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### `finditer`\n",
        "\n",
        "Чтобы найти все подстроки по некоторому шаблону и использовать их в *итераторе*, можно использовать функцию `finditer`."
      ],
      "metadata": {
        "id": "L4knYwlUtkNL"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "text = 'Эта строка написана 04.01.2022, а могла бы и 12.12.2021'\n",
        "regexp = r'\\d\\d\\.\\d\\d\\.\\d{4}'\n",
        "\n",
        "for m in re.finditer(regexp, text): \n",
        "    print('Дата', m[0], 'начинается с позиции', m.start())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ASPRyByepX_5",
        "outputId": "c5e9ff33-ebfe-49a7-88ad-2b869a8b827b"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Дата 04.01.2022 начинается с позиции 20\n",
            "Дата 12.12.2021 начинается с позиции 45\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### `sub`\n",
        "\n",
        "Чтобы заменить подстроки по некоторому шаблону, можно использовать функцию `sub`."
      ],
      "metadata": {
        "id": "srbsXFtYu5RD"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "text = 'Эта строка написана 04.01.2022, а могла бы и 12.12.2021'\n",
        "regexp = r'\\d\\d\\.\\d\\d\\.\\d{4}'\n",
        "replacement = 'DD.MM.YYYY'\n",
        "\n",
        "result = re.sub(regexp, replacement, text)\n",
        "print(result)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0yVunh_2pX9Y",
        "outputId": "b652406c-19ad-4e78-b9ca-53f598c0188d"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Эта строка написана DD.MM.YYYY, а могла бы и DD.MM.YYYY\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Объект типа `Match`\n",
        "\n",
        "Возвращаемым значением большинства функций модуля `re` является специальный объект типа `Match`.\n",
        "\n",
        "Этот объект содержит информацию о заданном шаблоне, тексте и результате поиска."
      ],
      "metadata": {
        "id": "zbRQM1Ksv2dH"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "text = 'Телефон 123-12-12'\n",
        "regexp = r'\\d\\d\\D\\d\\d'\n",
        "\n",
        "match = re.search(regexp, text) \n",
        "print(match)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "NuhuRt2Swyb7",
        "outputId": "a5ea75ac-5626-49e0-b0c8-e749643ae14c"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "<re.Match object; span=(9, 14), match='23-12'>\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Строка, по которой происходил поиск\n",
        "print(match.string)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "2yzOx3WexEJo",
        "outputId": "5ea53eae-3b15-4d0c-e048-bf286921826c"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Телефон 123-12-12\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Кортеж с начальной и конечной позициями найденной подстроки \n",
        "print(match.span())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "q_92JmnExPZ9",
        "outputId": "9c5ddc3c-32a2-4577-da9c-c34c18075f50"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "(9, 14)\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Найденная подстрока\n",
        "print(match.group())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "G1t8LkzJxfJ4",
        "outputId": "ad06e880-65e4-49be-c646-77c43dbc8a15"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "23-12\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Плохой пример регулярных выражений\n",
        "\n",
        "Для проверки правильности e-mail адреса может использоваться следующее регулярное выражение:\n",
        "\n",
        "```(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|\n",
        "2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])```\n",
        "\n",
        "Однако, поддерживать и разбираться в нём после написания почти невозможно. \n",
        "\n",
        "Регулярные выражения - не лекарство от всех болезней! Они должны быть (желательно) короткими и максимально понятными.\n"
      ],
      "metadata": {
        "id": "DdH0HLFS0XTL"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Задачи\n",
        "\n",
        "1. Найдите все «слова», написанные капсом (то есть строго заглавными), возможно внутри настоящих слов;\n",
        "1. Найдите слова, в которых есть русская буква, а когда-нибудь за ней цифра;\n",
        "1. Найдите все слова, начинающиеся с русской или латинской большой буквы;\n",
        "1. Найдите слова, которые начинаются на гласную;\n",
        "1. Найдите строчки, в которых есть символ `*`;\n",
        "1. Найдите строчки, в которых есть открывающая и когда-нибудь потом закрывающая скобки."
      ],
      "metadata": {
        "id": "H2cj7m_Pvwuz"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Найдите все «слова», написанные капсом (то есть строго заглавными), возможно внутри настоящих слов"
      ],
      "metadata": {
        "id": "FhR02gEozRJ0"
      }
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "gQVVWaTQpX7a"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Найдите слова, в которых есть русская буква, а когда-нибудь за ней цифра"
      ],
      "metadata": {
        "id": "VIYgaBTzzXmI"
      }
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "1CqZj9HQpX5V"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Найдите все слова, начинающиеся с русской или латинской большой буквы"
      ],
      "metadata": {
        "id": "EkAPIRP9zaMz"
      }
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "j_99iWZxpX2h"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Найдите слова, которые начинаются на гласную"
      ],
      "metadata": {
        "id": "Z6DFs61FzcjJ"
      }
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "ekgsQH85pX0d"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Найдите строчки, в которых есть символ `*`"
      ],
      "metadata": {
        "id": "zD3bXU4MzfpP"
      }
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "doGzN0ZxpXt5"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Найдите строчки, в которых есть открывающая и когда-нибудь потом закрывающая скобки"
      ],
      "metadata": {
        "id": "9I4wlLjWzidc"
      }
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "rKd_XIgbpXj_"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "n-8NbERQ003u"
      },
      "source": [
        "## Использованные и полезные ресурсы\n",
        "\n",
        "* https://habr.com/ru/post/349860/\n",
        "* https://regex101.com/\n",
        "* https://docs.python.org/3/library/re.html\n",
        "* https://www.w3schools.com/python/python_regex.asp"
      ]
    }
  ]
}